/**
 * 包装 Web Worker，简化收发消息，并补充类型定义
 *
 *
 * 使用方法（host 端）：
 * import SomeWorker from './some.worker?worker'
 *
 * type HostM = { ... }       // host 会发送的消息类型（worker 会收到的消息类型）
 * type WorkerM = { ... }     // worker 会发送的消息类型（host 会收到的消息类型）
 *
 * const worker = new WorkerContext<HostM, WorkerM>(SomeWorker)
 * worker.on(...)
 * worker.post(...)
 *
 * 使用方法（worker 端）：
 * type HostM = { ... }
 * type WorkerM = { ... }
 *
 * const worker = new WorkerContext<WorkerM, HostM>()
 * worker.on(...)
 * worker.post(...)
 */
import { InternalEventEmitter } from '@gnlab/utils/event'

// 可通过 Worker 传递的值类型
interface Messages {
  [name: string]: unknown
} // { name: data-type }
type Events<M extends Messages> = { [K in keyof M]: [M[K], void] }
interface WorkerMsg {
  name: string
  data: unknown
}

export class WorkerContext<
  PostM extends Messages,
  RecvM extends Messages,
> extends InternalEventEmitter<Events<RecvM>> {
  worker: Worker

  constructor(worker?: new () => Worker) {
    super()
    this.worker = typeof worker === 'function' ? new worker() : (self as unknown as Worker)
    this.worker.onmessage = this.handle.bind(this)
  }

  post<K extends keyof PostM>(name: K, data: PostM[K]) {
    this.worker.postMessage({ name, data })
  }

  protected handle(event: MessageEvent<WorkerMsg>) {
    const { name, data } = event.data
    this.emit(name, data as RecvM[string])
  }
}
